home *** CD-ROM | disk | FTP | other *** search
/ Scene 96 / Scene 96 International Edition (Zyklop Software) (Disc 2) (1997).iso / misc / coding / midas060 / samples / midp_dos / midpdisp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-01  |  22.1 KB  |  772 lines

  1. /*      MIDPDISP.C
  2.  *
  3.  * MIDAS Module Player v2.00 display handling routines
  4.  *
  5.  * Copyright 1995 Petteri Kangaslampi and Jarno Paananen
  6.  *
  7.  * This file is part of the MIDAS Sound System, and may only be
  8.  * used, modified and distributed under the terms of the MIDAS
  9.  * Sound System license, LICENSE.TXT. By continuing to use,
  10.  * modify or distribute this file you indicate that you have
  11.  * read the license and understand and accept it fully.
  12. */
  13.  
  14. #include <stdio.h>
  15. #include <conio.h>
  16. #include <string.h>
  17. #include <stdlib.h>
  18. #include <time.h>
  19.  
  20. #ifdef __WATCOMC__
  21. #include <i86.h>
  22. #else
  23. #include <dos.h>
  24. #endif
  25.  
  26. #include "midas.h"
  27. #include "vu.h"
  28. #include "vgatext.h"
  29. #include "midp.h"
  30.  
  31.  
  32. int             dispChannels = 0;       /* number of channels to display */
  33.  
  34. static uchar    oldDispMode;            /* old display mode */
  35. static uchar    oldRows;                /* old number of rows */
  36. static ushort   oldColumns;             /* old number of columns */
  37. static int      numRows;                /* number of character rows */
  38. static int      numColumns;             /* number of character columns */
  39. static int      modeChanged;            /* has display mode been changed? */
  40. static int      instNameRows;           /* number of instrument name rows */
  41.  
  42. #ifdef __16__
  43. //static uchar    *display = (uchar*) 0xB8000000;  /* ptr to display memory */
  44. #else
  45. //static uchar    *display = (uchar*) 0xB8000;   /* pointer to display memory */
  46. #endif
  47.  
  48. static char     s[32];                  /* temporary working area */
  49.  
  50.  
  51. /* Display top message: */
  52. static char     *dispTop =
  53. "MIDAS Module Player v" MIDPVERSTR " - Copyright 1995 Petteri Kangaslampi & "
  54. "Jarno Paananen";
  55.  
  56. /* Note strings: */
  57. char            *noteStr[13] =
  58.     {"C-", "C#", "D-", "D#", "E-", "F-", "F#", "G-", "G#", "A-", "A#", "B-"};
  59.  
  60. /* Hexadecimal numbers: */
  61. char            *hexTable = "0123456789ABCDEF";
  62.  
  63. /* Command name strings: */
  64. char            *commandStr[gmpNumCommands] = {
  65.     "",
  66.     "Arpeggio",
  67.     "Slide Up",
  68.     "Slide Down",
  69.     "Tone Porta",
  70.     "Vibrato",
  71.     "TPrt+VolSld",
  72.     "Vib+VolSld",
  73.     "TREMOLO",
  74.     "Set Panning",
  75.     "Sample Offs",
  76.     "VolumeSlide",
  77.     "Pos. Jump",
  78.     "Set Volume",
  79.     "Patt. Break",
  80.     "Set Speed",
  81.     "Set Tempo",
  82.     "FineSld Up",
  83.     "FineSld Dwn",
  84.     "Patt. Loop",
  85.     "Set Panning",
  86.     "Retrig Note",
  87.     "Fine VSl Up",
  88.     "Fine VSl Dn",
  89.     "Note Cut",
  90.     "Note Delay",
  91.     "Patt. Delay",
  92.     "Set M.Vol.",
  93.     "M.VolSlide",
  94.     "ST3 Retrig",
  95.     "Music Sync",
  96.     "XtrFnSld Up",
  97.     "XtrFnSld Dn",
  98.     "Pan Slide" };
  99.  
  100. /* Channel ID characters: */
  101. char            *channelID = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  102.  
  103.  
  104.  
  105.  
  106. #ifdef __32__
  107. #define VIDEOINT int386(0x10, ®s, ®s);
  108. #else
  109. #define VIDEOINT int86(0x10, ®s, ®s);
  110. #endif
  111.  
  112.  
  113. /****************************************************************************\
  114. *
  115. * Function:     void Set80x50(void)
  116. *
  117. * Description:  Sets up 80x50 VGA color alphanumeric display mode
  118. *
  119. \****************************************************************************/
  120.  
  121. static void Set80x50(void)
  122. {
  123.     static union REGS  regs;
  124.  
  125.     regs.w.ax = 3;
  126.     VIDEOINT
  127.  
  128.     regs.w.ax = 0x0500;
  129.     VIDEOINT
  130.  
  131.     regs.w.ax = 0x1202;
  132.     regs.h.bl = 0x30;
  133.     VIDEOINT
  134.  
  135.     regs.w.ax = 3;
  136.     VIDEOINT
  137.  
  138.     regs.w.ax = 0x1112;
  139.     regs.h.bl = 0;
  140.     VIDEOINT
  141.  
  142.     *((uchar*) 0x487) = (*((uchar*) 0x487)) | 1;
  143.  
  144.     regs.h.ah = 1;
  145.     regs.w.cx = 0x0600;
  146.     VIDEOINT
  147.  
  148.     *((uchar*) 0x487) = (*((uchar*) 0x487)) & 0xFE;
  149.  
  150.     outpw(0x3D4, 0x0814);
  151. }
  152.  
  153.  
  154.  
  155.  
  156. /****************************************************************************\
  157. *
  158. * Function:     void InitDisplay(void)
  159. *
  160. * Description:  Initializes MIDP display
  161. *
  162. \****************************************************************************/
  163.  
  164. void InitDisplay(void)
  165. {
  166.     /* Get old display mode, number of columns and number of rows: */
  167.     /* Warning! Works only for large model in real mode and _FLAT_ 32-bit
  168.        modes */
  169.     oldDispMode = *((uchar*) 0x449);
  170.     oldColumns = *((ushort*) 0x44A);
  171.     oldRows = *((uchar*) 0x484) + 1;
  172.  
  173.     /* Check if the current display mode is enough (at least 80 columns and
  174.        50 rows): */
  175.     if ( (oldColumns >= 80) && (oldRows >= 40) )
  176.     {
  177.         /* Use old display mode: */
  178.         numRows = oldRows;
  179.         numColumns = oldColumns;
  180.         modeChanged = 0;
  181.     }
  182.     else
  183.     {
  184.         /* Set up 80x50 display mode: */
  185.         Set80x50();
  186.         numRows = 50;
  187.         numColumns = 80;
  188.         modeChanged = 1;
  189.     }
  190.  
  191.     /* Set display width: */
  192.     vgaSetWidth(numColumns);
  193.  
  194.     /* Clear display memory: */
  195.     vgaFillRect(1, 1, numColumns, numRows, 0x07);
  196.  
  197.     /* Move cursor to the start of the message window: */
  198.     vgaMoveCursor(1, numRows-msgWindowHeight+1);
  199. }
  200.  
  201.  
  202.  
  203. /****************************************************************************\
  204. *
  205. * Function:     void DrawWindow(int x1, int y1, int x2, int y2,
  206. *                   uchar attrBackgroud, attrLitBorder, attrShadowBorder)
  207. *
  208. * Description:  Draws a window on the screen
  209. *
  210. * Input:        int x1                  x-coordinate of top left corner
  211. *               int y1                  y-coordinate of top left corner
  212. *               int x2                  x-coordinate of bottom right corner
  213. *               int y2                  y-coordinate of bottom right corner
  214. *               uchar attrBackgroud     background attribute
  215. *               uchar attrLitBorder     lit border attribute
  216. *               uchar attrShadowBorder  shadow border attribute
  217. *
  218. \****************************************************************************/
  219.  
  220. void DrawWindow(int x1, int y1, int x2, int y2, uchar attrBackground,
  221.     uchar attrLitBorder, uchar attrShadowBorder)
  222. {
  223.     int         y;
  224.  
  225.     /* Draw the top of the window: */
  226.     vgaDrawChar(x1, y1, '▐', attrLitBorder);
  227.     vgaDrawChars(x1+1, y1, '▀', attrLitBorder | (attrBackground & 0xF0),
  228.         x2 - x1 - 1);
  229.     vgaDrawChar(x2, y1, '▌', attrShadowBorder);
  230.  
  231.     /* Draw the middle rows of the window: */
  232.     for ( y = (y1+1); y < y2; y++ )
  233.     {
  234.         vgaDrawChar(x1, y, '▐', attrLitBorder);
  235.         vgaDrawChars(x1+1, y, ' ', attrBackground, x2-x1-1);
  236.         vgaDrawChar(x2, y, '▌', attrShadowBorder);
  237.     }
  238.  
  239.     /* Draw the bottom of the window: */
  240.     vgaDrawChar(x1, y2, '▐', attrLitBorder);
  241.     vgaDrawChars(x1+1, y2, '▄', attrShadowBorder | (attrBackground & 0xF0),
  242.         x2-x1-1);
  243.     vgaDrawChar(x2, y2, '▌', attrShadowBorder);
  244. }
  245.  
  246.  
  247.  
  248.  
  249. /****************************************************************************\
  250. *
  251. * Function:     void DrawBox(int x1, int y1, int x2, int y2,
  252. *                   uchar attrBackgroud, attrLitBorder, attrShadowBorder)
  253. *
  254. * Description:  Draws a shaded box (inside a window) on the screen. Note
  255. *               that the box is shaded to show it has been pressed "into"
  256. *               the window.
  257. *
  258. * Input:        int x1                  x-coordinate of top left corner
  259. *               int y1                  y-coordinate of top left corner
  260. *               int x2                  x-coordinate of bottom right corner
  261. *               int y2                  y-coordinate of bottom right corner
  262. *               uchar attrBackgroud     background attribute
  263. *               uchar attrLitBorder     lit border attribute
  264. *               uchar attrShadowBorder  shadow border attribute
  265. *
  266. \****************************************************************************/
  267.  
  268. void DrawBox(int x1, int y1, int x2, int y2, uchar attrBackground,
  269.     uchar attrLitBorder, uchar attrShadowBorder)
  270. {
  271.     int         y;
  272.  
  273.     /* Draw the top of the box: */
  274.     vgaDrawChar(x1, y1, '┌', attrShadowBorder);
  275.     vgaDrawChars(x1+1, y1, '─', attrShadowBorder, x2 - x1 - 1);
  276.     vgaDrawChar(x2, y1, '┐', attrLitBorder);
  277.  
  278.     /* Draw the middle rows of the box: */
  279.     for ( y = (y1+1); y < y2; y++ )
  280.     {
  281.         vgaDrawChar(x1, y, '│', attrShadowBorder);
  282.         vgaDrawChars(x1+1, y, ' ', attrBackground, x2-x1-1);
  283.         vgaDrawChar(x2, y, '│', attrLitBorder);
  284.     }
  285.  
  286.     /* Draw the bottom of the box: */
  287.     vgaDrawChar(x1, y2, '└', attrShadowBorder);
  288.     vgaDrawChars(x1+1, y2, '─', attrLitBorder, x2-x1-1);
  289.     vgaDrawChar(x2, y2, '┘', attrLitBorder);
  290. }
  291.  
  292.  
  293.  
  294.  
  295. /****************************************************************************\
  296. *
  297. * Function:     void DrawScreen(void)
  298. *
  299. * Description:  Draws the MIDP screen (without information)
  300. *
  301. \****************************************************************************/
  302.  
  303. void DrawScreen(void)
  304. {
  305.     int         y, x;
  306.     int         numch;
  307.     char        *s;
  308.  
  309.     /* If no module is loaded assume 4 channels: */
  310.     if ( dispChannels == 0 )
  311.         numch = 4;
  312.     else
  313.         numch = dispChannels;
  314.  
  315.     /* Draw display top message: */
  316.     x = (numColumns - strlen(dispTop)) / 2;
  317.     vgaWriteStr(1, 1, "", attrDispTop, x);
  318.     vgaWriteStr(x+1, 1, dispTop, attrDispTop, numColumns - x);
  319.  
  320.     /* Draw the main window: */
  321.     DrawWindow(1, 2, numColumns, numRows-msgWindowHeight, attrMainBg,
  322.         attrMainBorderLit, attrMainBorderSh);
  323.  
  324.     /* Draw the upper information box: */
  325.     x = (numColumns - 80) / 2;
  326.     DrawBox(2+x, 3, 79+x, 7, attrMainBg, attrMainLit, attrMainShadow);
  327.  
  328.     /* Draw the labels in the upper information box: */
  329.     vgaWriteStr(3+x, 4, "Module:", attrSongInfoLabel, 7);
  330.     vgaWriteStr(41+x, 4, "Type:", attrSongInfoLabel, 5);
  331.     vgaWriteStr(3+x, 5, "Mixing Rate:", attrSongInfoLabel, 12);
  332.     vgaWriteStr(27+x, 5, "Output Mode:", attrSongInfoLabel, 12);
  333.     vgaWriteStr(66+x, 5, "Time:", attrSongInfoLabel, 5);
  334.     vgaWriteStr(3+x, 6, "Length:", attrSongInfoLabel, 7);
  335.     vgaWriteStr(14+x, 6, "Position:", attrSongInfoLabel, 9);
  336.     vgaWriteStr(27+x, 6, "Pattern:", attrSongInfoLabel, 8);
  337.     vgaWriteStr(39+x, 6, "Row:", attrSongInfoLabel, 4);
  338.     vgaWriteStr(47+x, 6, "Tempo:", attrSongInfoLabel, 6);
  339.     vgaWriteStr(58+x, 6, "Speed:", attrSongInfoLabel, 6);
  340.     vgaWriteStr(68+x, 6, "Volume:", attrSongInfoLabel, 7);
  341.  
  342.     /* Draw the channel information box: */
  343.     DrawBox(2, 8, numColumns-1, 9+numch, attrMainBg, attrMainLit,
  344.         attrMainShadow);
  345.  
  346.     /* Draw the separators inside the channel information box: */
  347.     s = "\xFF\x01\x7F\x03 │\x7F\x01 │   │  │\x7F\x0E │";
  348.     s[1] = attrChanInfoSep;
  349.     s[7] = numColumns - 63;
  350.     for ( y = 9; y < (9+numch); y++ )
  351.     {
  352.         vgaWriteText(3, y, s);
  353.     }
  354.  
  355.     /* Draw the instrument name box: */
  356.     DrawBox(2, 10+numch, numColumns-1, numRows - msgWindowHeight - 1,
  357.         attrMainBg, attrMainLit, attrMainShadow);
  358.  
  359.     /* Calculate number of instrument name rows: */
  360.     instNameRows = numRows - msgWindowHeight - numch - 12;
  361. }
  362.  
  363.  
  364.  
  365.  
  366. /****************************************************************************\
  367. *
  368. * Function:     int InstCoords(int inst, int *x, int *y)
  369. *
  370. * Description:  Calculates the coordinates of an instrument name on the
  371. *               screen.
  372. *
  373. * Input:        int inst                instrument number
  374. *               int *x                  pointer to x-coordinate
  375. *               int *y                  pointer to y-coordinate
  376. *
  377. * Returns:      1 if instrument is visible, 0 if not.
  378. *
  379. \****************************************************************************/
  380.  
  381. int InstCoords(int inst, int *x, int *y)
  382. {
  383.     /* Check that the instrument name is visible: */
  384.     if ( (inst < firstInstName) || ((instNameMode == 0) &&
  385.         (inst >= (firstInstName + 2*instNameRows))) ||
  386.         ((instNameMode == 1) && (inst >= (firstInstName + instNameRows))) )
  387.         return 0;
  388.  
  389.     /* Check the appropriate instrument display mode and calculate the
  390.        x and y coordinates of the instrument name: */
  391.     if ( instNameMode == 0 )
  392.     {
  393.         *y = ((inst - firstInstName) % instNameRows) + 11 + dispChannels;
  394.         if ( (inst - firstInstName) < instNameRows )
  395.             *x = 3;
  396.         else
  397.             *x = (numColumns / 2) + 1;
  398.     }
  399.     else
  400.     {
  401.         *y = inst - firstInstName + 11 + dispChannels;
  402.         *x = 3;
  403.     }
  404.  
  405.     return 1;
  406. }
  407.  
  408.  
  409.  
  410.  
  411. /****************************************************************************\
  412. *
  413. * Function:     void DrawInstNames(void)
  414. *
  415. * Description:  Draws instrument names on the screen
  416. *
  417. \****************************************************************************/
  418.  
  419. void DrawInstNames(void)
  420. {
  421.     static int  x, y;
  422.     int         i, error, len;
  423.     static char *s;
  424.     static char *c;
  425.  
  426.     /* Draw the separator bar in the middle of the window if in two-column
  427.        mode: */
  428.     for ( y = 0; y < instNameRows; y++ )
  429.         vgaDrawChar(numColumns / 2, y + 11 + dispChannels, '│',
  430.             attrInstNameSeparator);
  431.  
  432.     /* Allocate memory for string buffer: */
  433.     if ( (error = memAlloc(256, &s)) != OK )
  434.         midasError(error);
  435.  
  436.     /* Allocate memory for channel ID characters: */
  437.     if ( (error = memAlloc(numChannels+1, &c)) != OK )
  438.         midasError(error);
  439.  
  440.     /* Build channel ID string: */
  441.     for ( i = 0; i < numChannels; i++ )
  442.         c[i] = channelID[i];
  443.  
  444.     c[i] = 0;
  445.  
  446.     /* Build and display information for all instruments: */
  447.     for ( i = 0; i < module->numInsts; i++ )
  448.     {
  449.         /* Calculate instrument name coordinates and check if it is visible:*/
  450.         if ( InstCoords(i+1, &x, &y) )
  451.         {
  452.             /* Check correct maximum string length: */
  453.             if ( instNameMode == 0 )
  454.             {
  455.                 if ( x > 3 )
  456.                     len = (numColumns / 2) - 3;
  457.                 else
  458.                     len = (numColumns / 2) - 4;
  459.             }
  460.             else
  461.             {
  462.                 len = numColumns - 4;
  463.             }
  464.  
  465.             /* Build instrument name string (includes channel ID characters,
  466.                instrument number and instrument name): */
  467.             sprintf(s, "%s %02X %s", c, i + 1,
  468.                 &module->instruments[i]->name[0]);
  469.             /* Draw info using color based on whether the instrument is
  470.                used or not: */
  471.             if ( module->instruments[i]->used )
  472.                 vgaWriteStr(x, y, s, attrUsedInstName, len+1);
  473.             else
  474.                 vgaWriteStr(x, y, s, attrUnusedInstName, len+1);
  475.         }
  476.     }
  477.  
  478.     /* If there are still free instrument name slots on the screen, clear
  479.        them: */
  480.     while ( InstCoords(i+1, &x, &y) )
  481.     {
  482.         /* Check correct maximum string length: */
  483.         if ( instNameMode == 0 )
  484.         {
  485.             if ( y > 3 )
  486.                 len = (numColumns / 2) - 3;
  487.             else
  488.                 len = (numColumns / 2) - 4;
  489.         }
  490.         else
  491.         {
  492.             len = numColumns - 4;
  493.         }
  494.  
  495.         /* Draw empty string: */
  496.         vgaWriteStr(x, y, "", attrUsedInstName, len+1);
  497.  
  498.         i++;
  499.     }
  500.  
  501.     /* Deallocate string buffer: */
  502.     if ( (error = memFree(s)) != OK )
  503.         midasError(error);
  504.  
  505.     /* Deallocate channel ID characters: */
  506.     if ( (error = memFree(c)) != OK )
  507.         midasError(error);
  508. }
  509.  
  510.  
  511.  
  512.  
  513. /****************************************************************************\
  514. *
  515. * Function:     void UpdateScreen(void)
  516. *
  517. * Description:  Updates the song playing information on screen
  518. *
  519. \****************************************************************************/
  520.  
  521. void UpdateScreen(void)
  522. {
  523.     time_t      currTime;
  524.     int         x, y;
  525.     int         hour, min, sec;
  526.     int         error;
  527.     static unsigned  vol;
  528.     int         i, n, ib;
  529.     gmpChannel  *chan;
  530.     static int  pan;
  531.     static char s[32];
  532.     static unsigned  meter;
  533.     static unsigned  position, volume, sample;
  534.     static ulong     rate;
  535.  
  536.     x = (numColumns - 80) / 2;
  537.  
  538.     /* Update the time display: */
  539.     if ( !paused )
  540.     {
  541.         currTime = time(NULL) - startTime - pauseTime;
  542.         hour = currTime / 3600;
  543.         min = ((currTime - 3600*hour) / 60) % 60;
  544.         sec = currTime % 60;
  545.         sprintf(&s[0], "%2i:%02i:%02i", hour, min, sec);
  546.         vgaWriteStr(71+x, 5, &s[0], attrSongInfo, 8);
  547.     }
  548.     else
  549.         vgaWriteStr(71+x, 5, "-PAUSED-", attrSongInfo, 8);
  550.  
  551.     /* Update the playing information in the top information box: */
  552.     vgaWriteByte(23+x, 6, info->position, attrSongInfo);
  553.     vgaWriteByte(35+x, 6, info->pattern, attrSongInfo);
  554.     vgaWriteByte(43+x, 6, info->row, attrSongInfo);
  555.     itoa(info->tempo, &s[0], 10);
  556.     vgaWriteStr(53+x, 6, &s[0], attrSongInfo, 3);
  557.     vgaWriteByte(64+x, 6, info->speed, attrSongInfo);
  558.     if ( (error = midasSD->GetMasterVolume(&vol)) != OK )
  559.         midasError(error);
  560.     vgaWriteByte(75+x, 6, vol, attrSongInfo);
  561.  
  562.     /* Draw channel information: */
  563.     y = 9;
  564.     for ( i = 0; i < numChannels; i++ )
  565.     {
  566.         /* Point chan to current channel structure: */
  567.         chan = &info->channels[i];
  568.  
  569.         /* Get channel panning position: */
  570.         if ( (error = midasSD->GetPanning(chan->sdChannel, &pan)) != OK )
  571.             midasError(error);
  572.  
  573.         /* Build panning string in s[]: */
  574.         switch ( pan )
  575.         {
  576.             case panLeft:
  577.                 mStrCopy(&s[0], "LFT");
  578.                 break;
  579.  
  580.             case panMiddle:
  581.                 mStrCopy(&s[0], "MID");
  582.                 break;
  583.  
  584.             case panRight:
  585.                 mStrCopy(&s[0], "RGT");
  586.                 break;
  587.  
  588.             case panSurround:
  589.                 mStrCopy(&s[0], "SUR");
  590.                 break;
  591.  
  592.             default:
  593.                 itoa(pan, &s[0], 10);
  594.                 break;
  595.         }
  596.  
  597.         /* Write panning information on screen: */
  598.         if ( i == activeChannel )
  599.             vgaWriteStr(3, y, &s[0], attrActChanMarker, 3);
  600.         else
  601.             vgaWriteStr(3, y, &s[0], attrChanInfo, 3);
  602.  
  603.         x = numColumns - 80;
  604.  
  605.         /* Write instrument and note only if there is a valid instrument and
  606.            the channel is not muted */
  607.         if ( (chan->instrument != -1) && (!chMuted[i]) )
  608.         {
  609.             /* Write instrument number: */
  610.             vgaWriteByte(7, y, chan->instrument + 1, attrChanInfo);
  611.  
  612.             /* Write instrument name: */
  613.             vgaWriteStr(10, y,
  614.                 &module->instruments[chan->instrument]->name[0],
  615.                 attrChanInfo, 14+x);
  616.  
  617.             /* Write note number only if there is a valid note: */
  618.             if ( chan->note != 0xFF )
  619.             {
  620.                 mStrCopy(&s[0], noteStr[chan->note & 0x0F]);
  621.                 s[2] = '0' + (chan->note >> 4);
  622.                 vgaWriteStr(25+x, y, &s[0], attrChanInfo, 3);
  623.             }
  624.             else
  625.                 vgaWriteStr(25+x, y, "", attrChanInfo, 3);
  626.         }
  627.         else
  628.         {
  629.             vgaWriteStr(7, y, "", attrChanInfo, 17+x);
  630.             vgaWriteStr(25+x, y, "", attrChanInfo, 3);
  631.         }
  632.  
  633.         /* Write channel volume: */
  634.         if ( chMuted[i] )
  635.             vgaWriteStr(29+x, y, "", attrChanInfo, 2);
  636.         else
  637.             vgaWriteByte(29+x, y, chan->trueVolume, attrChanInfo);
  638.  
  639.         /* Write command name and infobyte only if there is a command and
  640.            the channel is not muted: */
  641.         if ( (chan->status.command) && (chan->command > gmpcNone) &&
  642.             (chan->command < gmpNumCommands) && (!chMuted[i]) )
  643.         {
  644.             /* Get command name string: */
  645.             mStrCopy(&s[0], commandStr[chan->command]);
  646.  
  647.             /* Append command infobyte: */
  648.             n = mStrLength(&s[0]);
  649.             s[n] = ' ';
  650.             s[n+1] = hexTable[chan->infobyte >> 4];
  651.             s[n+2] = hexTable[chan->infobyte & 0x0F];
  652.             s[n+3] = 0;
  653.  
  654.             /* Write command string: */
  655.             vgaWriteStr(32+x, y, &s[0], attrChanInfo, 14);
  656.         }
  657.         else
  658.             vgaWriteStr(32+x, y, "", attrChanInfo, 14);
  659.  
  660.         /* Get VU meter value: */
  661.         if ( realVU )
  662.         {
  663.             /* Get playing rate for channel: */
  664.             if ( (error = midasSD->GetRate(i, &rate)) != OK )
  665.                 midasError(error);
  666.  
  667.             /* Get playing position for channel: */
  668.             if ( (error = midasSD->GetPosition(i, &position)) != OK )
  669.                 midasError(error);
  670.  
  671.             /* Get current sample handle for channel: */
  672.             if ( (error = midasSD->GetSample(i, &sample)) != OK )
  673.                 midasError(error);
  674.  
  675.             /* Get current volume for channel: */
  676.             if ( (error = midasSD->GetVolume(i, &volume)) != OK )
  677.                 midasError(error);
  678.  
  679.             if ( (sample > 0) && (rate > 0) )
  680.             {
  681.                 /* Get real VU meter value: */
  682.                 if ( (error = vuMeter(sample-1, rate, position, volume,
  683.                     &meter)) != OK )
  684.                     midasError(error);
  685.             }
  686.             else
  687.                 meter = 0;
  688.         }
  689.         else
  690.         {
  691.             meter = 0;
  692.         }
  693.  
  694.         /* If channel is muted, make VU-meter value zero: */
  695.         if ( chMuted[i] )
  696.             meter = 0;
  697.  
  698.         if ( meter > 64 )
  699.             meter = 64;
  700.  
  701.         /* Draw the VU meter: */
  702.         vgaDrawChars(47+x, y, '\xFE', attrVUMeters, (meter >> 1));
  703.         vgaDrawChars(47 + x + (meter >> 1), y, '\xFE', attrVUBlank,
  704.             32 - (meter >> 1));
  705.  
  706.         y++;
  707.     }
  708. }
  709.  
  710.  
  711.  
  712.  
  713. /****************************************************************************\
  714. *
  715. * Function:     void DrawSongInfo(void)
  716. *
  717. * Description:  Writes song-specific information on the screen
  718. *
  719. \****************************************************************************/
  720.  
  721. void DrawSongInfo(void)
  722. {
  723.     static unsigned mixRate, outputMode;
  724.     int         error;
  725.     int         x;
  726.  
  727.     /* Write song name: */
  728.     x = (numColumns - 80) / 2;
  729.     vgaWriteStr(10+x, 4, &module->name[0], attrSongInfo, 31);
  730.  
  731.     /* Write module type: */
  732.     switch ( module->playMode )
  733.     {
  734.         case gmpPT:
  735.             vgaWriteStr(46+x, 4, "Protracker module", attrSongInfo, 33);
  736.             break;
  737.  
  738.         case gmpFT2:
  739.             vgaWriteStr(46+x, 4, "Fasttracker ][ module", attrSongInfo, 33);
  740.             break;
  741.  
  742.         case gmpST3:
  743.             vgaWriteStr(46+x, 4, "Screamtracker ]I[ module", attrSongInfo, 33);
  744.             break;
  745.     }
  746.  
  747.     /* Write mixing rate: */
  748.     if ( (error = midasSD->GetMixRate(&mixRate)) != OK )
  749.         midasError(error);
  750.     mStrAppend(ltoa(mixRate, &s[0], 10), "Hz");
  751.     vgaWriteStr(15+x, 5, &s[0], attrSongInfo, 12);
  752.  
  753.     /* Write output mode: */
  754.     if ( (error = midasSD->GetMode(&outputMode)) != OK )
  755.         midasError(error);
  756.     if ( outputMode & sd16bit )
  757.         mStrCopy(&s[0], "16-bit ");
  758.     else
  759.         mStrCopy(&s[0], "8-bit ");
  760.     if ( outputMode & sdStereo )
  761.         mStrAppend(&s[0], "Stereo");
  762.     else
  763.         mStrAppend(&s[0], "Mono");
  764.     vgaWriteStr(39+x, 5, &s[0], attrSongInfo, 27);
  765.  
  766.     /* Write song length: */
  767.     vgaWriteByte(10+x, 6, module->songLength, attrSongInfo);
  768.  
  769.     /* Write instrument names: */
  770.     DrawInstNames();
  771. }
  772.